﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.Threading;
using dw = System.Drawing;

namespace client.app.world
{
    public class LightSource
    {
        public int X { get; set; }
        public int Y { get; set; }
        public int Radius { get; set; }

        int _x = 0, _y = 0, _radius = 0;
        public bool HasChange()
        {
            if (_x == X && _y == Y && _radius == Radius)
            {
                return false;
            }
            _x = X;
            _y = Y;
            _radius = Radius;
            return true;
        }

        public Rectangle Rect
        {
            get
            {
                return new Rectangle((int)(X - Radius), (int)(Y - Radius), Radius * 2, Radius * 2);
            }
        }
    }

    public class LightMask : comm.world.BObject, IBObject
    {
        Space _space = null;

        BlendState _blendState = new BlendState
        {
            AlphaDestinationBlend = Blend.SourceColor,
            ColorDestinationBlend = Blend.SourceColor,
            AlphaSourceBlend = Blend.Zero,
            ColorSourceBlend = Blend.Zero
        };
        SpriteBatch _spriteBatch = null;
        RenderTarget2D _renderTarget1 = null;

        RenderTarget2D _inputRenderTarget = null;
        RenderTarget2D _outputRrenderTarget = null;

        Texture2D _gradient = null;
        Texture2D _gradient2 = null;
        Texture2D _mask = null;
        List<LightSource> _lightSourceList = new List<LightSource>();
        Dictionary<Rectangle, RenderTarget2D> _renderTargetDic = new Dictionary<Rectangle, RenderTarget2D>();
        Bloom _bloom = null;
        comm.Timing _drawTiming = new comm.Timing();

        const int BLOCK_WIDTH = 100, BLOCK_HEIGTH = 100;
        Rectangle _viewRect;

        public LightMask(Space space)
        {
            _space = space;

            int w = _space.MapWidth,
                h = _space.MapHeight,
                bw = BLOCK_WIDTH,
                bh = BLOCK_HEIGTH,
                cw = (int)Math.Ceiling(w / (double)bw),
                ch = (int)Math.Ceiling(h / (double)bh);

            _viewRect = new Rectangle(0, 0,
                (int)Math.Ceiling(MainGame.Width / (double)_space.MapPathSize),
                (int)Math.Ceiling(MainGame.Height / (double)_space.MapPathSize));

            _renderTarget1 = new RenderTarget2D(MainGame.Instance.GraphicsDevice, _viewRect.Width, _viewRect.Height);
            _spriteBatch = new SpriteBatch(MainGame.Instance.GraphicsDevice);

            _gradient = MainGame.Instance.Content.Load<Texture2D>("gradient");
            _gradient2 = MainGame.Instance.Content.Load<Texture2D>("gradient2");
            _mask = MainGame.Instance.Content.Load<Texture2D>("fogmask");

            for (int x = 0; x < cw; x++)
            {
                for (int y = 0; y < ch; y++)
                {
                    var rect = new Rectangle(x * bw, y * bh, bw, bh);
                    var target = new RenderTarget2D(MainGame.Instance.GraphicsDevice, bw, bh, false, SurfaceFormat.Color, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
                    MainGame.Instance.GraphicsDevice.SetRenderTarget(target);
                    MainGame.Instance.GraphicsDevice.Clear(Color.Black);
                    _renderTargetDic.Add(rect, target);
                }
            }

            _inputRenderTarget = new RenderTarget2D(MainGame.Instance.GraphicsDevice, _viewRect.Width, _viewRect.Height);
            MainGame.Instance.GraphicsDevice.SetRenderTarget(_inputRenderTarget);
            MainGame.Instance.GraphicsDevice.Clear(Color.Black);

            _outputRrenderTarget = new RenderTarget2D(MainGame.Instance.GraphicsDevice, _viewRect.Width, _viewRect.Height);
            MainGame.Instance.GraphicsDevice.SetRenderTarget(_outputRrenderTarget);
            MainGame.Instance.GraphicsDevice.Clear(Color.White);

            _bloom = new Bloom(_inputRenderTarget, _outputRrenderTarget);
        }

        public void AddLightSource(LightSource lightSource)
        {
            lock (_lightSourceList)
            {
                _lightSourceList.Add(lightSource);
            }
        }
        public void BeginDraw(comm.TimeStat timeStat)
        {
            //if (_drawTiming.GetElapsedTime(timeStat, 1000 / 30) > 0)
            //{
            lock (_lightSourceList)
            {
                var begin = DateTime.Now;
                var list = new List<LightSource>();
                foreach (var lightSource in _lightSourceList)
                {
                    if (lightSource.HasChange())
                    {
                        list.Add(lightSource);
                    }
                }

                if (list.Count > 0)
                {
                    foreach (var rect in _renderTargetDic.Keys)
                    {
                        MainGame.Instance.GraphicsDevice.SetRenderTarget(_renderTargetDic[rect]);
                        _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
                        foreach (var lightSource in list)
                        {
                            var rt = lightSource.Rect;
                            if (rect.Intersects(rt))
                            {
                                rt.X -= rect.X;
                                rt.Y -= rect.Y;
                                _spriteBatch.Draw(_gradient2, rt, Color.White);
                            }
                        }
                        _spriteBatch.End();
                    }
                }
                var ms1 = (DateTime.Now - begin).TotalMilliseconds;

                begin = DateTime.Now;
                MainGame.Instance.GraphicsDevice.SetRenderTarget(_inputRenderTarget);
                _spriteBatch.Begin();
                foreach (var rect in _renderTargetDic.Keys)
                {
                    var rt = new Rectangle(
                        rect.X + (int)(_space.OffsetX / _space.MapPathSize),
                        rect.Y + (int)(_space.OffsetY / _space.MapPathSize),
                        rect.Width,
                        rect.Height);
                    if (_viewRect.Intersects(rt))
                    {
                        _spriteBatch.Draw(_renderTargetDic[rect], rt, Color.White);
                    }
                }
                _spriteBatch.End();
                var ms2 = (DateTime.Now - begin).TotalMilliseconds;

                begin = DateTime.Now;
                _bloom.Draw();
                var ms3 = (DateTime.Now - begin).TotalMilliseconds;

                begin = DateTime.Now;
                MainGame.Instance.GraphicsDevice.SetRenderTarget(_renderTarget1);
                MainGame.Instance.GraphicsDevice.Clear(Color.Black);
                _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
                _spriteBatch.Draw(_mask, new Rectangle(0, 0, MainGame.Width, MainGame.Height), Color.White);
                foreach (var lightSource in _lightSourceList)
                {
                    var rt = lightSource.Rect;
                    rt.X += (int)(_space.OffsetX / _space.MapPathSize);
                    rt.Y += (int)(_space.OffsetY / _space.MapPathSize);
                    if (_viewRect.Intersects(rt))
                    {
                        _spriteBatch.Draw(_gradient, rt, Color.White);
                    }
                }
                _spriteBatch.End();
                var ms4 = (DateTime.Now - begin).TotalMilliseconds;

                var am = ms1 + ms2 + ms3 + ms4;
                if (am > 0)
                {
                    mall++;

                    m1 += ms1 > 0 ? 1 : 0;
                    m2 += ms2 > 0 ? 1 : 0;
                    m3 += ms3 > 0 ? 1 : 0;
                    m4 += ms4 > 0 ? 1 : 0;

                    //Console.WriteLine((am) + " " + mall + " hsy(" + m1 + "):" + ms1 + " merge(" + m2 + "):" + ms2 + " bloom(" + m3 + "):" + ms3 + " all list(" + m4 + "):" + ms4);
                }
            }
            //}
        }
        public void Draw(comm.TimeStat timeStat)
        {
            var begin = DateTime.Now;

            var rt = new Rectangle(0, 0, _viewRect.Width * _space.MapPathSize, _viewRect.Height * _space.MapPathSize);

            _spriteBatch.Begin(SpriteSortMode.Deferred, _blendState);
            _spriteBatch.Draw(_renderTarget1, rt, Color.White);
            _spriteBatch.Draw(_outputRrenderTarget, rt, Color.White);
            _spriteBatch.End();

            var ms = (DateTime.Now - begin).TotalMilliseconds;
            if (ms > 0)
            {
                //Console.WriteLine("LightMask draw " + ms);
            }
        }

        int m1 = 0, m2 = 0, m3 = 0, m4 = 0, mall = 0;

        protected override void OnUpdate(comm.TimeStat timeStat)
        {
        }
    }
}
